﻿#include <list>
#include "metainfo.h"
#include "dynamicremoteobject.h"
#include "dynamicmetacreator.h"
#include "remoteobjectnode.h"
#include "metafunction.h"
#include "metaproperty.h"
#include "metasignal.h"
#include "remoteobject_p.h"

DataOutputStream& operator << (DataOutputStream& s,const PropertyData& t){
    s << t.name;
    s << t.type;
    s << t.notifier;
    return s;
}

DataInputStream& operator >> (DataInputStream& s,PropertyData& t){
    s >> t.name;
    s >> t.type;
    s >> t.notifier;
    return s;
}

DataOutputStream& operator << (DataOutputStream& s,const FunctionData& t){
    s << t.name;
    s << t.ReturnType;
    s << t.ArgType;
    return s;
}

DataInputStream& operator >> (DataInputStream& s,FunctionData& t){
    s >> t.name;
    s >> t.ReturnType;
    s >> t.ArgType;
    return s;
}

DataOutputStream& operator << (DataOutputStream& s,const SignalData& t){
    s << t.name;
    s << t.type;
    return s;
}

DataInputStream& operator >> (DataInputStream& s,SignalData& t){
    s >> t.name;
    s >> t.type;
    return s;
}

DataOutputStream& operator << (DataOutputStream& s,const DynamicMetaInfoData& t){
   s << t.className;
   s << t.Properties;
   s << t.Functions;
   s << t.SignalDatas;
   s << t.Notifiers;
    return s;
}

DataInputStream& operator >> (DataInputStream& s,DynamicMetaInfoData& t){
    s >> t.className;
    s >> t.Properties;
    s >> t.Functions;
    s >> t.SignalDatas;
	s >> t.Notifiers;
    return s;
}


class RemoteObjectMessageFactory:public MessageFactory{
public:
	template<typename T>
	void RegisterMessage(const wchar_t* name) {
		creators[name] = []() {
			return new T();
		};
	}

	RemoteObjectMessageFactory() {
		RegisterMessage<HelloMessage>(RO_HELLO);
		RegisterMessage<RequestObjectList>(RO_RequestObjectList);
		RegisterMessage<ReplyObjectList>(RO_ReplyObjectList);
		RegisterMessage<RequestObject>(RO_RequestObject);
		RegisterMessage<NewObject>(RO_NewObject);
		RegisterMessage<ReplyObject>(RO_ReplyObject);
		RegisterMessage<UnRegisterObject>(RO_UnRegisterObject);
		RegisterMessage<RequestObjectMeta>(RO_RequestObjectMeta);
		RegisterMessage<ReplyObjectMeta>(RO_ReplyObjectMeta);
		RegisterMessage<ObjectClosed>(RO_ObjectClosed);
		RegisterMessage<PropertyUpdate>(RO_PropertyUpdate);
		RegisterMessage<PropertyPush>(RO_PropertyPush);
		RegisterMessage<SignalInvoked>(RO_SignalInvoked);
		RegisterMessage<SlotRequest>(RO_SlotRequest);
		RegisterMessage<SlotFinished>(RO_SlotFinished);
	}

Message * CreateMessage(MessageType type) override{
    Message * ret = NULL;

	if (creators.count(type))
	{
		return creators.at(type)();
	}

    return ret;
}
std::map<MessageType, std::function<Message*()>> creators;
};

class InitFactory
{
public:
    InitFactory(){
        Message::RegisterFactory(&factory);
    }

    ~InitFactory(){
        Message::UnRegisterFactory(&factory);
    }

    RemoteObjectMessageFactory factory;
};
static InitFactory init;


RemoteObjectNodeBasePrivate::~RemoteObjectNodeBasePrivate()
{

}

bool containsInfo(const std::vector<std::string> &info, const std::string& target) {
	for (const auto &a : info) {
		if (a == target)
		{
			return true;
		}
	}
	return false;
}

DynamicMetaInfoData ExtractMetaInfo(MetaInfo meta) {
	DynamicMetaInfoData ret;

	ret.className = meta.ClassName();

	int funcount = meta.FunctionCount();
	for (int i = 0; i < funcount; i++) {
		FunctionData data;

		auto fun = meta.GetFunction(i);

		if (!containsInfo(fun.GetFunctionInfos(), "RO_FUNCTION")) {
			continue;
		}

		data.name = fun.GetName();
		std::vector<std::string> arg;
		for (auto i : fun.GetParamTypes()) {
			arg.push_back(MetaType(i).Name());
		}
		data.ArgType = arg;
		data.ReturnType = MetaType(fun.GetReturnType()).Name();
		ret.Functions[i] = data;
	}

	int propertyCount = meta.PropertyCount();
	for (int i = 0; i < propertyCount; i++) {
		auto property = meta.GetProperty(i);
		PropertyData data;

		if (!containsInfo(property.GetPropertyInfo(), "RO_PROPERTY"))
		{
			continue;
		}

		data.name = property.Name();

		auto notifier = property.GetNotifier();
		data.notifier = notifier.Index();

		data.type = MetaType(property.Type()).Name();
		ret.Properties[i] = data;
	}

	int signalCount = meta.SignalCount();
	for (int i = 0; i < signalCount; i++) {
		auto signal = meta.GetSignal(i);

		std::map<int, SignalData>* signalData = NULL;

		SignalData data;
		if (containsInfo(signal.GetSignalInfo(), "RO_SIGNAL"))
		{
			signalData = &ret.SignalDatas;
		}
		else if (containsInfo(signal.GetSignalInfo(), "RO_NOTIFIER")) {
			signalData = &ret.Notifiers;
		}
		else
		{
			continue;
		}

		std::vector<std::string> arg;
		for (auto i : signal.GetParamTypes()) {
			arg.push_back(MetaType(i).Name());
		}

		data.name = signal.Name();
		data.type = arg;
		(*signalData)[i] = data;
	}

	return ret;
}

//将外部的元信息以子类的形式导入Super元信息中
MetaInfo CreateDynamicMetaInfo(const DynamicMetaInfoData &data)
{
	MetaInfo Super = DynamicRemoteObject::staticMetaInfo();
	DynamicMetaCreator creator(Super.Size(), [=](void* target) {
		Super.Destory(target);
	}, data.className.c_str(), Super, [](void* p) {
		DynamicRemoteObject * o = static_cast<DynamicRemoteObject*>(p);
		return o;
	});

	for (auto & i : data.Functions)
	{
		int index = i.first;
		auto &data = i.second;
		std::vector<MetaTypeId> args;
		for (auto j : data.ArgType) {
			args.push_back(MetaType(j).Id());
		}
		MetaTypeId returnType = MetaType(data.ReturnType.c_str()).Id();
		auto &&helper = creator.addFunction(data.name.c_str(), returnType, args);
		helper.setFunction([=](void* o, const void**param, void* r ) {
			DynamicRemoteObject* obj = static_cast<DynamicRemoteObject*>(o);
			RemoteObjectNode* node = dynamic_cast<RemoteObjectNode*>(obj->GetNode());
			VariantList p;
			for (int i = 0; i < args.size(); i++) {
				p.push_back(Variant(param[i], args[i]));
			}

			if (returnType == 0) {
				obj->CallRemoteFunctionImp(index, p, false);
			}
			else {
				auto ret = obj->CallRemoteFunctionImp(index, p, true);
				ret->WaitForFinished(true);
				Variant va = ret->GetReturnValue();

				va.AsignTo(r);
			}
		});
		helper.addInfo((std::string("REMOTE:") + std::to_string(index)).c_str());
		helper.finish();
	}

	for (auto & i : data.Properties)
	{
		int index = i.first;
		auto &data_s = i.second;

		MetaTypeId type = MetaType(data_s.type.c_str()).Id();

		auto &&helper = creator.addProperty(data_s.name.c_str(), type);

		helper.addGetter([=](void* o,const void** param,void* ret) {
			const DynamicRemoteObject* obj = static_cast<const DynamicRemoteObject*>(o);
			Variant v = obj->GetRemotePropertyImp(index);
			v.AsignTo(ret);
		});

		helper.addSetter([=](void* o, const void** param, void* ret) {
			DynamicRemoteObject* obj = static_cast<DynamicRemoteObject*>(o);
			const void * val = *(param);
			obj->PushRemotePropertyImp(index, Variant(val, type));
		});

		const SignalData& s = data.Notifiers.at(data_s.notifier);

		helper.addNotifier(s.name.c_str());

		helper.addInfo((std::string("REMOTE:") + std::to_string(index)).c_str());

		helper.finish();
	}

	std::map<int, SignalData> signals;
	for (auto &i : data.SignalDatas) {
		signals.insert(i);
	}

	for (auto &i : data.Notifiers) {
		signals.insert(i);
	}

	for (auto & i : signals)
	{
		int index = i.first;
		auto &data = i.second;
		std::vector<MetaTypeId> args;
		for (auto j : data.type) {
			args.push_back(MetaType(j).Id());
		}
		auto &&helper = creator.addSignal(data.name.c_str(), args);
		helper.setSignal([=](void*o) {
			DynamicRemoteObject* obj = static_cast<DynamicRemoteObject*>(o);
			return obj->GetRemoteSignalImp(index);
		});
		helper.addInfo((std::string("REMOTE:") + std::to_string(index)).c_str());
		helper.finish();
	}

	std::string SignatureInfo = "SIGNATURE:" + std::to_string(GetSignature(data));

	creator.addClassInfo(SignatureInfo.c_str());

	return creator.finish();
}

template<typename T>
int Hash(const T& t) {
	return std::hash<T>()(t);
}

unsigned long long GetSignature(const DynamicMetaInfoData & data) {
	unsigned long long ret = 0;

	ret += Hash(data.className);

	for (auto &i : data.Functions) {
		ret += Hash(i.first);

		for (auto j : i.second.ArgType) {
			ret += Hash(j);
		}

		ret += Hash(i.second.name);
		ret += Hash(i.second.ReturnType);
	}

	for (auto &i : data.Properties) {
		ret += Hash(i.first);
		ret += Hash(i.second.name);
		ret += Hash(i.second.notifier);
		ret += Hash(i.second.type);
	}

	for (auto &i : data.SignalDatas) {
		ret += Hash(i.first);
		for (auto j : i.second.type) {
			ret += Hash(j);
		}
		ret += Hash(i.second.name);
	}

	for (auto &i : data.Notifiers) {
		ret += Hash(i.first);
		for (auto j : i.second.type) {
			ret += Hash(j);
		}
		ret += Hash(i.second.name);
	}

	return ret;
}

unsigned long long GetSignature(MetaInfo info)
{
	static const std::string target = "SIGNATURE:";
	if (info == DynamicRemoteObject::staticMetaInfo()) {
		return 0;
	}

	for (auto &s : info.GetClassInfo()) {
		if (s.find(target)) {
			std::string sig(s.begin() + target.size(), s.end());
			return std::atoll(sig.c_str());
		}
	}

	return 0;
}
